package com.zrq.gencode.util;

import com.zrq.gencode.cfg.GenCfg;
import com.zrq.gencode.exception.ConfigationException;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;

/**
 * Velocity模板工具类
 *
 * @author zhong
 */
public class Velocity {
	private static final Logger logger = LoggerFactory.getLogger(Velocity.class);

	private static final VelocityEngine VELOCITY_ENGINE = new VelocityEngine();

	private final static String GEN = "gen";

	private static final Map<String, Template> MAP = new ConcurrentHashMap<>();

	static {
		VELOCITY_ENGINE.setProperty(org.apache.velocity.runtime.RuntimeConstants.RESOURCE_LOADER, "classpath");
		VELOCITY_ENGINE.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
		VELOCITY_ENGINE.setProperty("input.encoding", "UTF-8");
		VELOCITY_ENGINE.setProperty("output.encoding", "UTF-8");
		// 增加解析器池大小以支持多线程环境
		if (GenCfg.enableMultithreading) {
			VELOCITY_ENGINE.setProperty("parser.pool.size", 100);
		}
		// 启用模板缓存
		VELOCITY_ENGINE.setProperty("resource.manager.cache.class", "org.apache.velocity.runtime.resource.ResourceCacheImpl");
		VELOCITY_ENGINE.init();
	}

	private static Template getTemplate(String name) {
		return VELOCITY_ENGINE.getTemplate(name);
	}

	private static VelocityContext getVelocityContext(Object obj) {
		VelocityContext ctx = new VelocityContext();
		ctx.put(GEN, obj);
		return ctx;
	}

	/**
	 * 根据模板生成代码文件
	 *
	 * @param templateName 模板路径
	 * @param name         生成类名
	 * @param obj          信息
	 */
	public static void done(String templateName, String name, Object obj) {
		File file = new File(name);
		try {
			// 创建父级目录 - 使用更细粒度的锁，按目录路径锁定
			if (!file.getParentFile().exists()) {
				synchronized (file.getParentFile().getAbsolutePath().intern()) {
					if (!file.getParentFile().exists()) {
						file.getParentFile().mkdirs();
						logger.debug("创建新目录:{}", file.getParentFile().getPath());
					}
				}
			}

			// 检查文件是否存在
			if (!file.exists()) {
				// 使用文件路径作为锁，避免全局锁定
				synchronized (file.getAbsolutePath().intern()) {
					if (!file.exists()) {
						file.createNewFile();
						logger.debug("创建新文件:{}", name);
					}
				}
			} else {
				logger.debug("文件:{}已存在，进行覆盖", name);
			}

			// 处理模板
			StringWriter sw = new StringWriter();
			Template tmp = MAP.get(templateName);
			if (tmp == null) {
				tmp = getTemplate(templateName);
				MAP.put(templateName, tmp);
			}
			tmp.merge(getVelocityContext(obj), sw);
			String result = sw.toString();

			// 写入文件
			try (FileWriter fileWriter = new FileWriter(file)) {
				fileWriter.write(result);
				fileWriter.flush();
			}
		} catch (IOException e) {
			logger.error("生成文件时发生错误: {}", name, e);
			throw new ConfigationException("生成文件失败: " + name, e);
		}
	}
}